package net.dethnull.joscontrol.gui;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import net.dethnull.joscontrol.osc.Client;
import net.dethnull.joscontrol.osc.Osc;

/**
 * Project: jOSControl
 * Package: net.dethnull.joscontrol.gui
 * Author: dethnull
 * Date: 2/1/13
 * <p/>
 * Description:
 * Main class that holds the GUI logic for the application
 */
public class JOSControl extends Application {

    private final int _WIDTH_ = 800, _HEIGHT_ = 480;

    StackPane rootWindow;
    Scene scene;
    Osc osc;

    GridPane mainTabContainerGrid;
    GridPane maintTabServInfoGrid;
    GridPane mainTabAssignmentGrid;
    GridPane debugLogTabGrid;

    TabPane tabPane;
    Tab tabMain;
    Tab tabSettings;
    Tab tabDebugLog;

    TableView<Client> tableMain;
    TableColumn<Client, String> colIpAddress;
    TableColumn<Client, String> colAddrPattern;
    TableColumn<Client, String> colAssignedKey;

    Button btnStart;
    Button btnSetKey;

    static TextField tFieldServerIp;
    TextField tFieldServerPort;
    TextField tFieldKeyAssignment;

    static TextArea txtAreaLog;
    static TextArea txtAreaErrorLog;

    Text txtServerIp;
    Text txtServerPort;
    Text txtAssignKey;
    Text txtDebugWindowInfo;
    Text txtErrorWindow;
    Text txtMainTabInfo;

    @Override
    public void start(Stage stage) throws Exception {
        stage.setTitle("jOSControl - The universal OSC controller");
        scene = new Scene(rootWindow, _WIDTH_, _HEIGHT_);
        stage.resizableProperty().setValue(false);

        rootWindow.getChildren().add(tabPane);
        tabPane.getTabs().addAll(tabMain, tabSettings, tabDebugLog);

        tabMain.setContent(mainTabContainerGrid);
        ColumnConstraints colWidth = new ColumnConstraints();
        colWidth.setPercentWidth(55);
        mainTabContainerGrid.getColumnConstraints().add(colWidth);

        ColumnConstraints debugTabConstraints = new ColumnConstraints();
        debugTabConstraints.setPercentWidth(100);
        tabDebugLog.setContent(debugLogTabGrid);
        debugLogTabGrid.getColumnConstraints().add(debugTabConstraints);


        GridPane.setConstraints(txtDebugWindowInfo, 0, 0);
        GridPane.setConstraints(txtAreaLog, 0, 1);
        GridPane.setConstraints(txtErrorWindow, 0, 2);
        GridPane.setConstraints(txtAreaErrorLog, 0, 3);
        debugLogTabGrid.getChildren().add(txtDebugWindowInfo);
        debugLogTabGrid.getChildren().add(txtErrorWindow);
        debugLogTabGrid.getChildren().add(txtAreaLog);
        debugLogTabGrid.getChildren().add(txtAreaErrorLog);

        GridPane.setConstraints(tableMain, 0, 0);
        GridPane.setConstraints(maintTabServInfoGrid, 0, 1);
        GridPane.setConstraints(mainTabAssignmentGrid, 1, 0);


        GridPane.setConstraints(txtAssignKey, 0, 0);
        GridPane.setConstraints(tFieldKeyAssignment, 1, 0);
        GridPane.setConstraints(btnSetKey, 1, 1);

        GridPane.setConstraints(txtMainTabInfo, 0, 2, 2, 2);


        mainTabAssignmentGrid.getChildren().add(tFieldKeyAssignment);
        mainTabAssignmentGrid.getChildren().add(txtAssignKey);
        mainTabAssignmentGrid.getChildren().add(btnSetKey);
        mainTabAssignmentGrid.getChildren().add(txtMainTabInfo);


        mainTabContainerGrid.getChildren().addAll(tableMain, mainTabAssignmentGrid, maintTabServInfoGrid);


        maintTabServInfoGrid.add(txtServerIp, 0, 0);
        maintTabServInfoGrid.add(tFieldServerIp, 1, 0);
        maintTabServInfoGrid.add(txtServerPort, 2, 0);
        maintTabServInfoGrid.add(tFieldServerPort, 3, 0);
        maintTabServInfoGrid.add(btnStart, 4, 0);

        tableMain.getColumns().addAll(colIpAddress, colAddrPattern, colAssignedKey);

        colIpAddress.setCellValueFactory    (new PropertyValueFactory<Client, String>("ipAddress"));
        colAddrPattern.setCellValueFactory  (new PropertyValueFactory<Client, String>("addressPattern"));
        colAssignedKey.setCellValueFactory  (new PropertyValueFactory<Client, String>("keyValue"));


        btnSetKey.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                try {
                    char keyText = tFieldKeyAssignment.getText().charAt(0);
                    Client data = tableMain.getSelectionModel().getSelectedItem();
                    data.set_key(keyText);
                } catch (Exception e) {
                    addToDebugLog(e.getMessage());
                }


            }
        });

        btnStart.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                if (!osc.getHasStarted()) {
                    if (tFieldServerPort.getText() != null &&
                        tFieldServerPort.getText().trim().isEmpty()) {
                        addToDebugLog("Port field was empty, defaulting to 22556");
                        osc.setPort(22556);
                    } else {
                        //TODO: Validate submitted port
                        int port = Integer.valueOf(tFieldServerPort.getText().trim());
                        osc.setPort(port);
                    }
                    tFieldServerPort.setEditable(false);
                    new Thread(osc).start();
                    btnStart.setText("Stop");
                } else if (osc.getHasStarted()) {
                    btnStart.setText("Start");
                    osc.stop();
                    tFieldServerPort.setEditable(true);
                }
            }
        });

        tableMain.setItems(osc.getClients());
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void init() {
        try {
            rootWindow                  = new StackPane();
            tabPane                     = new TabPane();
            tabMain                     = new Tab("Main");
            tabSettings                 = new Tab("Settings");
            tabDebugLog                 = new Tab("Debug Log");


            tableMain                   = new TableView<>();
                tableMain.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

            colIpAddress                = new TableColumn<>("Ip Address");
                colIpAddress.setMinWidth(100);
                colIpAddress.setMaxWidth(100);
            colAddrPattern              = new TableColumn<>("Address Pattern");
            colAssignedKey              = new TableColumn<>("Assigned Key");

            btnStart                    = new Button("Start");
            btnSetKey                   = new Button("Set Key");

            maintTabServInfoGrid        = new GridPane();
                maintTabServInfoGrid.setPadding(new Insets(10));
            mainTabContainerGrid        = new GridPane();
                mainTabContainerGrid.setPadding(new Insets(5));
            mainTabAssignmentGrid       = new GridPane();
                //Insets(top, right, bottom, left)
                mainTabAssignmentGrid.setPadding(new Insets(0,0,0,10));
            debugLogTabGrid             = new GridPane();
                debugLogTabGrid.setPadding(new Insets(10));

            //TODO: Get actual host IP address and put it in the text box
            tFieldServerIp              = new TextField();
                tFieldServerIp.setEditable(false);
            tFieldServerPort            = new TextField("22556");
                tFieldServerPort.setPrefWidth(65);
            tFieldKeyAssignment         = new TextField();
            txtAreaLog                  = new TextArea();
                txtAreaLog.setMaxWidth(_WIDTH_ - 10);
                txtAreaLog.setMaxHeight(_HEIGHT_ - 60);
            txtAreaErrorLog = new TextArea();
                txtAreaErrorLog.setMaxWidth(_WIDTH_ - 10);
                txtAreaErrorLog.setMaxHeight(_HEIGHT_ - 60);



            txtServerIp                 = new Text("Server IP: ");
            txtServerPort               = new Text("Port: ");
            txtAssignKey                = new Text("Assign Key");
            txtDebugWindowInfo          = new Text("Information about OSC transactions will be posted here");
            txtErrorWindow              = new Text("Error messages will be pushed to this window");
            txtMainTabInfo              = new Text(
                "Rules for key input are as follows:\n"
                +"\tOnly alpha-numeric character, 0-9 & a-z\n"
                +"\tAs implied above, no special characters\n"
                +"\tOnly Lower case for now\n\n"
                +"How to begin:\n"
                +"\tSet the port number at the bottom\n"
                +"\tThen click start\n"
                +"\tPress OSC buttons to fill table\n"
                +"\tClick on a row, put key in on the right\n"
                +"\tThen click Set Key\n"
                +"At the moment there is no indication\n"
                +"that a key is being pressed in the UI"
            );


            osc = new Osc();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static void setServerIpText(String serverIP) {
        tFieldServerIp.setText(serverIP);
    }

    @Override
    public void stop() {
        try {
            if (osc.getHasStarted()) {
                osc.stop();
            }
            super.stop();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

    public static void addToDebugLog(String string) {
        txtAreaLog.appendText(string + "\n");
    }

    public static void main(String[] args) {
        launch(args);
    }
}
